#include <core/common/global.h>
#include <core/common/string.h>
#include <core/common/multi-thread.h>
#include <core/common/log.h>

#if !defined(CORE_COMMON_DISABLE_SSL__) && !defined(CORE_COMMON_STATIC__)
	#include <openssl/err.h>
#endif

//
// class Mutex implement
//

core::common::Mutex::Mutex()
{
	valid_ = false;
	create();
}

core::common::Mutex::Mutex( const std::string &name )
{
	valid_ = false;
	name_ = name;
	create();
}

core::common::Mutex::~Mutex()
{
	if( valid_ )
	{
		unlock();
		close();
	}
}

bool core::common::Mutex::create()
{
	VALIDATE_ERROR_RETURN(valid_, ERROR_ALREADY_EXISTS, false);

	valid_  = true;

#ifdef OS_PLATFORM_WINDOWS
	//try
	//{
	//	::InitializeCriticalSection(&object_);
	//}
	//catch(...)
	//{
	//	__ULOG_FATAL(__ULOG_FMT_ERR("common::Mutex", "Create object failed"), __UERR_CODE, __UERR_STR);
	//}

	object_ = ::CreateMutexA(NULL, FALSE, name_.size() > 0 ? name_.c_str() : NULL);
	if( NULL == object_ )
	{
		__ULOG_ERROR(__ULOG_FMT_ERR("common::Mutex", "Create object failed"), __UERR_CODE, __UERR_STR);
		valid_ = false;
	}
#else
	pthread_mutexattr_t mutexAttr;
	pthread_mutexattr_init(&mutexAttr);
	pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_ERRORCHECK_NP);
	if( pthread_mutex_init(&object_, &mutexAttr) != 0 )
	{
		__ULOG_ERROR(__ULOG_FMT_ERR("common::Mutex", "Create object failed"), __UERR_CODE, __UERR_STR);
		valid_ = false;
	}
	pthread_mutexattr_destroy(&mutexAttr);
#endif

	return valid_;
}

bool core::common::Mutex::create( const std::string &name )
{
	VALIDATE_ERROR_RETURN(valid_, ERROR_ALREADY_EXISTS, false);

	name_ = name;
	return create();
}

bool core::common::Mutex::close()
{
	VALIDATE_ERROR_RETURN(!valid_, ERROR_NOT_READY, false);

#ifdef OS_PLATFORM_WINDOWS
	//::DeleteCriticalSection(&object_);
	::CloseHandle(object_);
#else
	pthread_mutex_destroy(&object_);
#endif

	valid_ = false;
	return true;
}

bool core::common::Mutex::isValid() const
{
	return valid_;
}

bool core::common::Mutex::lock() const
{
	VALIDATE_ERROR_RETURN(!valid_, ERROR_NOT_READY, false);

#ifdef OS_PLATFORM_WINDOWS
	//::EnterCriticalSection(&object_);
	return WAIT_OBJECT_0 == ::WaitForSingleObject(object_, INFINITE);
	//return true;
#else
	return pthread_mutex_lock(&object_) == 0;
#endif
}

bool core::common::Mutex::tryLock() const
{
	VALIDATE_ERROR_RETURN(!valid_, ERROR_NOT_READY, false);

#ifdef OS_PLATFORM_WINDOWS
	return WAIT_OBJECT_0 == ::WaitForSingleObject(object_, 1);
	//return ::TryEnterCriticalSection(&object_) == TRUE;
#else
	return pthread_mutex_trylock(&object_) == 0;
#endif
}

bool core::common::Mutex::unlock() const
{
	VALIDATE_ERROR_RETURN(!valid_, ERROR_NOT_READY, false);

#ifdef OS_PLATFORM_WINDOWS
	return ::ReleaseMutex(object_) ? true : false;
	//::LeaveCriticalSection(&object_);
	//return true;
#else
	return pthread_mutex_unlock(&object_) == 0;
#endif
}

//
// class ReadWriteMutex
//
#ifndef ANDROID

core::common::ReadWriteMutex::ReadWriteMutex()
{
#ifdef OS_PLATFORM_WINDOWS
	try
	{
		// windows implement as critical section now
		::InitializeCriticalSection(&reader_);
		::InitializeCriticalSection(&writer_);
	}
	catch(...)
	{
		__ULOG_FATAL(__ULOG_FMT_ERR("common::ReadWriteMutex", "Create object failed"), __UERR_CODE, __UERR_STR);
	}

	lockedReader_ = false;
	readerCount_  = 0;
	noReaderEvent_ = ::CreateEvent(NULL, TRUE, TRUE, NULL);
	writerEvent_   = ::CreateEvent(NULL, TRUE, TRUE, NULL);
	if( NULL == noReaderEvent_ || NULL == writerEvent_ )
	{
		__ULOG_FATAL(__ULOG_FMT_ERR("common::ReadWriteMutex", "Create events for objectfailed"), __UERR_CODE, __UERR_STR);
	}
#else
	pthread_rwlockattr_t mutexAttr;
	pthread_rwlockattr_init(&mutexAttr);
	//pthread_rwlockattr_settype(&mutexAttr, PTHREAD_MUTEX_ERRORCHECK_NP);
	if( pthread_rwlock_init(&object_, &mutexAttr) != 0 )
	{
		__ULOG_FATAL(__ULOG_FMT_ERR("common::ReadWriteMutex", "Create rw object failed"), __UERR_CODE, __UERR_STR);
	}
	pthread_rwlockattr_destroy(&mutexAttr);
#endif
}

core::common::ReadWriteMutex::~ReadWriteMutex()
{
	unlock();
#ifdef OS_PLATFORM_WINDOWS
	DeleteCriticalSection(&reader_);
	DeleteCriticalSection(&writer_);
	CloseHandle(noReaderEvent_);
	CloseHandle(writerEvent_);
#else
	pthread_rwlock_destroy(&object_);
#endif
}

#ifdef OS_PLATFORM_WINDOWS
void core::common::ReadWriteMutex::incReaderCount() const
{
	EnterCriticalSection(&reader_);

	readerCount_ ++;
	ResetEvent(noReaderEvent_);

	LeaveCriticalSection(&reader_);
}

void core::common::ReadWriteMutex::decReaderCount() const
{
	EnterCriticalSection(&reader_);
	
	assert(readerCount_ > 0);

	readerCount_ --;
	if( 0 == readerCount_ )
	{
		SetEvent(noReaderEvent_);
	}

	LeaveCriticalSection(&reader_);
}
#endif //OS_PLATFORM_WINDOWS

bool core::common::ReadWriteMutex::readLock() const
{
#ifdef OS_PLATFORM_WINDOWS
	while( true )
	{
		WaitForSingleObject(writerEvent_, INFINITE);
		incReaderCount();
		if( WaitForSingleObject(writerEvent_, 0) != WAIT_OBJECT_0 )
		{
			decReaderCount();
		}
		else
		{
			// success
			break;
		}
	}

	lockedReader_ = true;
	return true;
#else
	return pthread_rwlock_rdlock(&object_) == 0;
#endif
}

bool core::common::ReadWriteMutex::writeLock() const
{
#ifdef OS_PLATFORM_WINDOWS
	EnterCriticalSection(&writer_);

	WaitForSingleObject(writerEvent_, INFINITE);
	ResetEvent(writerEvent_);
	WaitForSingleObject(noReaderEvent_, INFINITE);
	lockedReader_ = false;
	LeaveCriticalSection(&writer_);
	return true;
#else
	return pthread_rwlock_wrlock(&object_) == 0;
#endif
}

bool core::common::ReadWriteMutex::tryReadLock() const
{
#ifdef OS_PLATFORM_WINDOWS
	if( WaitForSingleObject(writerEvent_, 0) != WAIT_OBJECT_0 )
	{
		return false;
	}

	incReaderCount();
	if( WaitForSingleObject(writerEvent_, 0) != WAIT_OBJECT_0 )
	{
		decReaderCount();
		return false;
	}

	lockedReader_ = true;
	return true;
#else
	return pthread_rwlock_tryrdlock(&object_) == 0;
#endif
}

bool core::common::ReadWriteMutex::tryWriteLock() const
{
#ifdef OS_PLATFORM_WINDOWS
	if( !TryEnterCriticalSection(&writer_) )
	{
		core::common::setErrorCode(ERROR_ALREADY_EXISTS);
		return false;
	}

	bool bResult = false;
	do 
	{
		if( WaitForSingleObject(writerEvent_, 0) != WAIT_OBJECT_0 ||
			readerCount_ > 0 )
		{
			break;
		}

		ResetEvent(writerEvent_);
		WaitForSingleObject(noReaderEvent_, INFINITE);
		lockedReader_ = false;
		bResult = true;
	} while (false);

	LeaveCriticalSection(&writer_);
	return bResult;
#else
	return pthread_rwlock_trywrlock(&object_) == 0;
#endif
}

bool core::common::ReadWriteMutex::unlock() const
{
#ifdef OS_PLATFORM_WINDOWS
	if( lockedReader_ )
	{
		if( readerCount_ <= 0 )
		{
			core::common::setErrorCode(ERROR_NOT_READY);
			return false;
		}
		decReaderCount();
	}
	else
	{
		SetEvent(writerEvent_);
	}
	return true;
#else
	return pthread_rwlock_unlock(&object_) == 0;
#endif
}
#endif
//
// class core::common::AutoLock implement
//

core::common::AutoLock::AutoLock( const Mutex *mutex, bool initLock /* = true */ ) : 
mutex_(mutex),
locked_(false)
{
	if( initLock ) lock();
}

core::common::AutoLock::AutoLock( const Mutex &mutex, bool initLock /* = true */ ) : 
mutex_(&mutex),
locked_(false)
{
	if( initLock ) lock();
}

core::common::AutoLock::~AutoLock()
{
	if( locked_ ) unlock();
}

bool core::common::AutoLock::lock() const
{
	assert(NULL != mutex_);

	if( locked_ ) return true;

	locked_ = mutex_->lock();
	return locked_;
}

bool core::common::AutoLock::unlock() const
{
	assert(NULL != mutex_);

	if( !locked_ ) return true;

	locked_ = !mutex_->unlock();
	return !locked_;
}

//
// class AutoReadLock implement
//

#ifndef ANDROID

core::common::AutoReadLock::AutoReadLock( const ReadWriteMutex *mutex, bool initLock /* = true */ ) : 
mutex_(mutex),
locked_(false)
{
	if( initLock ) lock();
}

core::common::AutoReadLock::~AutoReadLock()
{
	if( locked_ ) unlock();
}

bool core::common::AutoReadLock::lock() const
{
	assert(NULL != mutex_);

	locked_ = mutex_->readLock();
	return locked_;
}

bool core::common::AutoReadLock::unlock() const
{
	assert(NULL != mutex_);

	locked_ = !mutex_->unlock();
	return !locked_;
}

//
// class AutoWriteLock implement
//

core::common::AutoWriteLock::AutoWriteLock( const ReadWriteMutex *mutex, bool initLock /* = true */ ) : 
mutex_(mutex),
locked_(false)
{
	if( initLock ) lock();
}

core::common::AutoWriteLock::~AutoWriteLock()
{
	if( locked_ ) unlock();
}

bool core::common::AutoWriteLock::lock() const
{
	assert(NULL != mutex_);

	locked_ = mutex_->writeLock();
	return locked_;
}

bool core::common::AutoWriteLock::unlock() const
{
	assert(NULL != mutex_);

	locked_ = !mutex_->unlock();
	return !locked_;
}
#endif

//
// class Event implement
//

core::common::Event::Event()
{
	valid_ = false;
	error_ = ERROR_SUCCESS;

	create();
}

core::common::Event::Event( const std::string &name )
{
	valid_ = false;
	error_ = ERROR_SUCCESS;
	name_ = name;
	create();
}

core::common::Event::~Event()
{
	if( valid_ )
	{
		close();
	}
}

bool core::common::Event::create()
{
	VALIDATE_ERROR_RETURN(valid_, ERROR_ALREADY_EXISTS, false);

#ifdef OS_PLATFORM_WINDOWS
	object_ = CreateEventA(NULL, FALSE, FALSE, name_.size() > 0 ? name_.c_str() : NULL);
	valid_ = (NULL != object_);
#else
	error_ = (uint32)pthread_cond_init(&object_, NULL);
	valid_ = (0 == error_);
#endif

	return valid_;
}

bool core::common::Event::create( const std::string &name )
{
	VALIDATE_ERROR_RETURN(valid_, ERROR_ALREADY_EXISTS, false);

	name_ = name;
	return create();
}

bool core::common::Event::close()
{
	VALIDATE_ERROR_RETURN(!valid_, ERROR_NOT_READY, false);

#ifdef OS_PLATFORM_WINDOWS
	CloseHandle(object_);	
#else
	pthread_cond_destroy(&object_);
#endif

	valid_ = false;
	return true;
}

bool core::common::Event::isValid() const
{
	return valid_;
}

bool core::common::Event::wait( int timeoutMs ) const
{
	VALIDATE_ERROR_RETURN(!valid_, ERROR_NOT_READY, false);

#ifdef OS_PLATFORM_WINDOWS
	error_ = WaitForSingleObject(object_, timeoutMs);
	return WAIT_OBJECT_0 == error_;
#else
	locker_.lock();

	if( timeoutMs < 0 )
	{
		error_ = pthread_cond_wait(&object_, &locker_.object_);
	}
	else
	{
		const long n1E9 = 1000 * 1000 * 1000;
		timeval timeNow = {0, 0};
		timespec timeout = {0, 0};
		gettimeofday(&timeNow, 0);

		timeout.tv_sec = timeNow.tv_sec + timeoutMs/1000;
		timeout.tv_nsec = timeNow.tv_usec * 1000 + (timeoutMs % 1000) * 1000 * 1000;

		if( timeout.tv_nsec > n1E9 )
		{
			timeout.tv_sec += timeout.tv_nsec / n1E9;
			timeout.tv_nsec %= n1E9;
		}

		error_ = pthread_cond_timedwait(&object_, &locker_.object_, &timeout);
	}

	locker_.unlock();

	return 0 == error_;
#endif
}

bool core::common::Event::serviceWait( int timeoutMs ) const
{
#ifdef OS_PLATFORM_WINDOWS
	VALIDATE_ERROR_RETURN(!valid_, ERROR_NOT_READY, false);

	error_ = WaitForSingleObject(object_, timeoutMs);
	return WAIT_OBJECT_0 == error_;
#else
	// we do sleep under non-windows because of daemon wait for signal only, no event
	usleep( ((__useconds_t)timeoutMs) * 1000 );
	return false;
#endif
}

bool core::common::Event::trigger() const
{
	VALIDATE_ERROR_RETURN(!valid_, ERROR_NOT_READY, false);

#ifdef OS_PLATFORM_WINDOWS
	return SetEvent(object_) == TRUE;
#else
	return 0 == pthread_cond_signal(&object_);
#endif
}

bool core::common::Event::reset() const
{
	VALIDATE_ERROR_RETURN(!valid_, ERROR_NOT_READY, false);

#ifdef OS_PLATFORM_WINDOWS
	return ResetEvent(object_) == TRUE;
#else
	// no need for linux, auto release
	// even pthread_cond_signal will not set the signal when no thread wait.
	return true;
#endif
}

bool core::common::Event::broadcast() const
{
	VALIDATE_ERROR_RETURN(!valid_, ERROR_NOT_READY, false);

#ifdef OS_PLATFORM_WINDOWS
	return SetEvent(object_) == TRUE;
#else
	return 0 == pthread_cond_broadcast(&object_);
#endif
}

bool core::common::Event::isTimeout() const
{
#ifdef OS_PLATFORM_WINDOWS
	return WAIT_TIMEOUT == error_;
#else
	return ETIMEDOUT == error_;
#endif
}

//
// class ThreadHelper
//

core::common::THREAD_INIT_NOTIFY_CALLBACK core::common::ThreadHelper::initNotifier_ = NULL;
core::common::THREAD_EXIT_NOTIFY_CALLBACK core::common::ThreadHelper::exitNotifier_ = NULL;

void core::common::ThreadHelper::registerNotify( THREAD_INIT_NOTIFY_CALLBACK initNotifier, THREAD_EXIT_NOTIFY_CALLBACK exitNotifier )
{
	initNotifier_ = (core::common::THREAD_INIT_NOTIFY_CALLBACK)initNotifier;
	exitNotifier_ = (core::common::THREAD_EXIT_NOTIFY_CALLBACK)exitNotifier;
}

//
// class Thread
//

#ifdef OS_PLATFORM_WINDOWS
	const HANDLE core::common::Thread::kInvalidHandle = INVALID_HANDLE_VALUE;
#else
	const pthread_t core::common::Thread::kInvalidHandle = (pthread_t)-1;
#endif

core::common::Thread::Thread()
{
	object_  = Thread::kInvalidHandle;
	enabled_   = false;
	running_   = false;
	threadStackSize_ = 0;
	threadPriority_  = -1;
	threadPolicy_    = -1;
	threadId_   = 0;
	autoDelete_ = false;
	autoDeleteCallback_ = NULL;
}

core::common::Thread::~Thread()
{
	assert(!isRunning());
	//terminate();
}

bool core::common::Thread::start()
{
	if( isObjectValid() )
	{
		return false;
	}

	bool success = false;
	uint32 errorCode = 0;

	enabled_  = true;
	running_  = true;
	threadId_ = 0;

#ifdef OS_PLATFORM_WINDOWS
	unsigned threadId = 0;

	object_ = (HANDLE)_beginthreadex(NULL, threadStackSize_, threadWrapper, this, 0, &threadId);
	if( threadPriority_ >= 0 )
	{
		int nWinThreadPriority = THREAD_PRIORITY_NORMAL;

		if( threadPriority_ < 25 ) nWinThreadPriority = THREAD_PRIORITY_LOWEST;
		else if( threadPriority_ < 50 ) nWinThreadPriority = THREAD_PRIORITY_BELOW_NORMAL;
		else if( threadPriority_ == 50 ) nWinThreadPriority = THREAD_PRIORITY_NORMAL;
		else if( threadPriority_ < 75 ) nWinThreadPriority = THREAD_PRIORITY_ABOVE_NORMAL;
		else nWinThreadPriority = THREAD_PRIORITY_HIGHEST;

		if( !::SetThreadPriority(object_, nWinThreadPriority) )
		{
			__ULOG_ERROR(__ULOG_FMT_ERR("common::Thread", "Set thread priority failed"), __UERR_CODE, __UERR_STR);
		}
	}

	errorCode = core::common::getErrorCode();
	success = isObjectValid();
	threadId_ = threadId;
#else
	pthread_attr_t objectAttr;
	pthread_attr_init(&objectAttr);
	pthread_attr_setdetachstate(&objectAttr, PTHREAD_CREATE_DETACHED);
	if( 0 != threadStackSize_ )
	{
		pthread_attr_setstacksize(&objectAttr, threadStackSize_);
	}
	if( threadPriority_ >= 0 )
	{
		if( -1 == threadPolicy_ )
		{
			threadPolicy_ = SCHED_RR;/* SCHED_FIFO, SCHED_RR*/
		}

		pthread_attr_setschedpolicy(&objectAttr, threadPolicy_);
#ifndef ANDROID
		pthread_attr_setinheritsched(&objectAttr, PTHREAD_EXPLICIT_SCHED);
#endif

		struct sched_param nScheduleParam;
		memset(&nScheduleParam, 0, sizeof(nScheduleParam));

		nScheduleParam.sched_priority = threadPriority_; // 1 - 99;
		pthread_attr_setschedparam(&objectAttr, &nScheduleParam);
	}

	errorCode = pthread_create(&object_, &objectAttr, threadWrapper, this);
	success = (errorCode == 0);
	threadId_ = (size_t)object_;

	pthread_attr_destroy(&objectAttr);
#endif

	if( !success )
	{
		// restore _beginthread or pthread_create's error
		core::common::setErrorCode(errorCode);

		object_ = Thread::kInvalidHandle;
		enabled_ = false;
		running_ = false;
	}

	return success;
}

bool core::common::Thread::stop()
{
	if( !isObjectValid() || !enabled_ )
	{
		return false;
	}

	enabled_ = false;
	return true;
}

bool core::common::Thread::stopAndJoin()
{
	if( !isObjectValid() )
	{
		return false;
	}

	stop();
	while( running_ )
	{
		core::common::Thread::sleep(10);
	}

	return true;
}

bool core::common::Thread::terminate()
{
	if( !isObjectValid() )
	{
		return false;
	}

	enabled_ = false;
	running_ = false;

	bool bSuccess = false;

#ifdef OS_PLATFORM_WINDOWS
	bSuccess = (TerminateThread(object_, 0) == TRUE);
	CloseHandle(object_);
#else
#ifndef ANDROID
	bSuccess = (pthread_cancel(object_) == 0);
#endif
#endif

	object_   = Thread::kInvalidHandle;
	threadId_ = 0;
	return bSuccess;
}

bool core::common::Thread::isRunning() const
{
	return running_;
}

#ifdef OS_PLATFORM_WINDOWS
uintptr_t __STDCALL core::common::Thread::threadWrapper( void *param )
#else
void *core::common::Thread::threadWrapper( void *param )
#endif
{
#ifdef OS_PLATFORM_WINDOWS
	// initialize random seed
	srand((unsigned int)core::common::getHighResolutionTime());
#endif

	if( core::common::ThreadHelper::initNotifier_ )
	{
		(* core::common::ThreadHelper::initNotifier_)();
	}

	Thread *thisPtr = (Thread *)param;
	thisPtr->run();

	thisPtr->threadId_ = 0;
#ifdef OS_PLATFORM_WINDOWS
	HANDLE thread     = thisPtr->object_;
	thisPtr->object_  = Thread::kInvalidHandle;
	CloseHandle(thread);
#else
	thisPtr->object_   = Thread::kInvalidHandle;
#endif
	thisPtr->running_  = false;

	// auto delete
	if( thisPtr->autoDelete_ && NULL != thisPtr->autoDeleteCallback_ )
	{
		thisPtr->autoDeleteCallback_(thisPtr);
		thisPtr = NULL;
	}

#if !defined(CORE_COMMON_DISABLE_SSL__) && !defined(CORE_COMMON_STATIC__) && !defined(USE_SYSTEM_SSL)
	::ERR_remove_state(0);
#endif

	if( core::common::ThreadHelper::exitNotifier_ )
	{
		(* core::common::ThreadHelper::exitNotifier_)();
	}

#ifdef OS_PLATFORM_WINDOWS
	_endthreadex(0);
	return 0;
#else
	return NULL;
#endif
}

void core::common::Thread::sleep( int millSecs )
{
#ifdef OS_PLATFORM_WINDOWS
	::Sleep(millSecs);
#else
	usleep(((__useconds_t)millSecs) * 1000);
#endif
}

size_t core::common::Thread::getCurrentId()
{
#ifdef OS_PLATFORM_WINDOWS
	return (size_t)::GetCurrentThreadId();
#else
	return (size_t)pthread_self();
#endif
}

//
// class common::RunnableThread
//
core::common::RunnableThread::RunnableThread( core::common::IRunnable *runnable )
{
	runnableId_ = 0;
	runnable_   = runnable;
}

core::common::RunnableThread::RunnableThread( size_t runnableId, core::common::IRunnable *runnable )
{
	runnableId_ = runnableId;
	runnable_   = runnable;
}

core::common::RunnableThread::~RunnableThread()
{
	runnable_ = NULL;
}

void core::common::RunnableThread::run()
{
	assert(NULL != runnable_);
	
	runnable_->run(this);
}

core::common::IRunnable *core::common::RunnableThread::attach( core::common::IRunnable *runnable )
{
	core::common::IRunnable *oldRunnable = runnable_;

	runnable_ = runnable;
	return oldRunnable;
}

bool core::common::RunnableThread::stop()
{
	assert(NULL != runnable_);

	if( !core::common::Thread::stop() )
	{
		return false;
	}

	runnable_->stop();
	return true;
}
